#import "BSNetAPIClient.h"
#import "ImageCompressUntils.h"
@interface BSNetAPIClient()
@property (nonatomic, copy)  NSDictionary *errorInfo;
@property (nonatomic, strong) NSOperationQueue *queue;
@property (nonatomic, strong) NSMutableArray <NSDictionary*>*imageJsonArr;
@end
@implementation BSNetAPIClient

static BSNetAPIClient *_sharedClient = nil;
+ (instancetype)sharedClient {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedClient = [[BSNetAPIClient alloc] initWithBaseURL:[NSURL URLWithString:[BSNetAPIClient baseURLStr]]];;
    });
    return _sharedClient;
}
+ (void)changeClient {
    _sharedClient = [[BSNetAPIClient alloc] initWithBaseURL:[NSURL URLWithString:[BSNetAPIClient baseURLStr]]];
}

- (id)initWithBaseURL:(NSURL *)url {
    self = [super initWithBaseURL:url];
    if (!self) return nil;
    self.requestSerializer.timeoutInterval = 10.0f;
    self.responseSerializer = [AFJSONResponseSerializer serializer];
    self.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/plain", @"text/javascript", @"text/json", @"text/html", nil];
    return self;
}

- (void)requestWithPath:(nullable NSString *)aPath
                 params:(nullable NSDictionary *)params
         viewController:(nullable UIViewController*)vc
                   type:(NetworkMethodType)type
                   info:(nullable NSArray<NSNumber*>*)infoArr
                  block:(nullable PostNetWorkBock)block {
    if (PostUserGet(@"close")){
        block(nil,NO); return;
    }
    self.requestSerializer.timeoutInterval = 15.0f;
    if (![aPath isKindOfClass:NSString.class] || aPath.length <= 0) return;
    aPath = [aPath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    BOOL showLoad = ([infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(ShowLoading)] != NSNotFound);
    if (showLoad) [BaseAlert showHudWithText:PostLadingMessage inView:vc.view];
    NSMutableDictionary *headInfo = NSMutableDictionary.new;
    NSString *token = [PostManage shareInstance].token;
    if (token) [headInfo setValue:[@"Bearer " stringByAppendingString:token] forKey:@"Authorization"];
    [headInfo setValue:@"apple" forKey:@"source"];
    if (([infoArr isKindOfClass:NSArray.class] &&
         [infoArr indexOfObject:@(RequestJSON)] != NSNotFound)) {
        self.requestSerializer = [AFJSONRequestSerializer serializer];
        [self.requestSerializer setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    }else{
        self.requestSerializer = [AFHTTPRequestSerializer serializer];
        [self.requestSerializer setValue:@"application/x-www-form-urlencoded;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    }
    switch (type) {
        case Get: {
            [self GET:aPath parameters:params headers:headInfo progress:^(NSProgress * _Nonnull downloadProgress) {
            } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:responseObject autoShowError:infoArr vc:vc block:block];
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:error autoShowError:infoArr vc:vc block:block];
            }];
        }
        break;
        case Post: {
            [self POST:aPath parameters:params headers:headInfo progress:^(NSProgress * _Nonnull uploadProgress) {
            } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:responseObject autoShowError:infoArr vc:vc block:block];
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:error autoShowError:infoArr vc:vc block:block];
            }];
        }
        break;
        case Put: {
            [self PUT:aPath parameters:params headers:headInfo success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:responseObject autoShowError:infoArr vc:vc block:block];
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:error autoShowError:infoArr vc:vc block:block];
            }];
        }
        break;
        case Delete: {
            [self DELETE:aPath parameters:params headers:headInfo success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
                [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:responseObject autoShowError:infoArr vc:vc block:block];
            } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
                [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:error autoShowError:infoArr vc:vc block:block];
            }];
        }
        break;
    }
}

- (void)requestImageWithPath:(nullable NSString *)aPath
                      params:(nullable NSDictionary *)params
              viewController:(nullable UIViewController*)vc
                      images:(NSArray <UIImage*>*)images
                       names:(nullable NSArray <NSString*>*)names
                        info:(nullable NSArray<NSNumber*>*)infoArr
                       block:(nullable PostNetWorkBock)block{
    BOOL uploadMustAll = ([infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(UploadMustAll)] != NSNotFound);
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    self.queue = queue;
    self.imageJsonArr = NSMutableArray.new;
    queue.maxConcurrentOperationCount = 4;
    BOOL result = YES;
    NSBlockOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // 回到主线程执行，方便更新 UI 等
            if (block) block(self.imageJsonArr,result);
        }];
    }];

    for (int i = 0; i<images.count; i++){
        @autoreleasepool {
            NSBlockOperation *uploadOperation = [NSBlockOperation blockOperationWithBlock:^{
                NSString *name = nil;
                if ([names isKindOfClass:NSArray.class] && names.count > i) {
                    name = names[i];
                }
                [self requestOneImageWithPath:aPath params:params viewController:vc image:images[i] name:name info:infoArr queue:YES block:^(id  _Nullable data, BOOL result) {
                    if (result) {
                        [self.imageJsonArr addObject:data];
                    }else{
                        if (uploadMustAll) {
                            [self.queue cancelAllOperations];
                        }
                    }
                }];
            }];
            [completionOperation addDependency:uploadOperation];
            [queue addOperation:uploadOperation];
        }
    }
    [queue addOperation:completionOperation];
}

- (void)requestOneImageWithPath:(nullable NSString *)aPath
                         params:(nullable NSDictionary *)params
                 viewController:(nullable UIViewController*)vc
                          image:(UIImage*)image
                           name:(nullable NSString*)name
                           info:(nullable NSArray<NSNumber*>*)infoArr
                          queue:(BOOL)queue
                          block:(nullable PostNetWorkBock)block{
    NSMutableDictionary *headInfo = NSMutableDictionary.new;
    NSString *token = [PostManage shareInstance].token;
    if (token) [headInfo setValue:[@"Bearer " stringByAppendingString:token] forKey:@"Authorization"];
    BOOL showLoad = ( [infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(ShowLoading)] != NSNotFound);
    if (showLoad) [BaseAlert showHudWithText:PostLadingMessage inView:vc.view];
    NSDateFormatter *dateFormat = [NSDateFormatter new];
    [dateFormat setDateFormat:@"yyyyMMddHHmmss"];
    dispatch_semaphore_t semaphore = nil;
    if (self.queue && queue)
        semaphore = dispatch_semaphore_create(0);
    [self POST:aPath parameters:params headers:headInfo constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSString *defaultFileName = [dateFormat stringFromDate:[NSDate date]];
        if (name) defaultFileName = name;
        [ImageCompressUntils compressedImageFiles:image imageKB:200 imageBlock:^(NSData * _Nullable imageData) {
            [formData appendPartWithFileData:imageData
                                        name:@"file"
                                    fileName:[defaultFileName stringByAppendingString:@".jpg"]
                                    mimeType:@"image/jpeg"];
        }];
    } progress:^(NSProgress * _Nonnull uploadProgress) {

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:responseObject uploadFile:YES autoShowError:infoArr vc:vc block:block];
        if (self.queue && queue)
           dispatch_semaphore_signal(semaphore);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        
        [self handleResponse:(NSHTTPURLResponse *)task.response responseJSON:error uploadFile:YES autoShowError:infoArr  vc:vc block:block];
        if (self.queue && queue)
           dispatch_semaphore_signal(semaphore);
    }];
    if (self.queue && queue)
       dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

- (void)requestOneImageWithPath:(nullable NSString *)aPath
                         params:(nullable NSDictionary *)params
                 viewController:(nullable UIViewController*)vc
                          image:(UIImage*)image
                           name:(nullable NSString*)name
                           info:(nullable NSArray<NSNumber*>*)infoArr
                          block:(nullable PostNetWorkBock)block{
    [self requestOneImageWithPath:aPath params:params viewController:vc image:image name:name info:infoArr queue:NO block:block];
}

#pragma mark - responseJSON Error
-(void)handleResponse:(NSHTTPURLResponse*)response
       responseJSON:(id)responseJSON
         uploadFile:(BOOL)uploadFile
      autoShowError:(NSArray*)infoArr
                 vc:(nullable UIViewController*)vc
              block:(nullable PostNetWorkBock)block{
    BOOL showError = ([infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(ShowErrorAlert)] != NSNotFound);
    BOOL showAuto = ([infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(ShowAutoHide)] != NSNotFound);
    BOOL showLoad = ([infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(ShowLoading)] != NSNotFound);
    BOOL showSucces = ([infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(ShowSuccessAlert)] != NSNotFound);
    BOOL showNotLogin = ([infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(ShowNotLogin)] != NSNotFound);
    BOOL returnErrCode = ([infoArr isKindOfClass:NSArray.class] && [infoArr indexOfObject:@(ReturnErrCode)] != NSNotFound);
    
    if (showLoad) [BaseAlert hideHudInView:vc.view];
    NSLog(@"responseJSON:%@",responseJSON);
    NSString *errorStr = nil;
    NSInteger errorCode = 0;
    if (response.statusCode == 200) {
        if ([responseJSON isKindOfClass:NSDictionary.class]) {
            if (responseJSON[@"code"]) errorCode = [responseJSON[@"code"] intValue];
            if (errorCode == 200) {
                if (showSucces) {
                    NSString *successMessage = uploadFile?@"上传成功":((responseJSON[@"msg"] && [responseJSON[@"msg"] isKindOfClass:NSString.class] && [responseJSON[@"msg"] length])?responseJSON[@"msg"]:@"操作成功");
                    if (showAuto) {
                        PostAutoAlert(successMessage);
                    }else{
                        PostSuccessView(successMessage,vc.view)
                    }
                }
                if (block) block((responseJSON[@"data"] && ![responseJSON[@"data"] isKindOfClass:[NSNull class]])?responseJSON[@"data"]:responseJSON[@"msg"],YES);
                return;
            }else if(errorCode == 921 || errorCode == 911){
                errorStr = responseJSON[@"msg"];
                if (!showNotLogin) {
                    if (!errorStr || ([errorStr isKindOfClass:NSString.class] && !errorStr.length)) errorStr = @"请求失败,请稍后再试";
                    if (PostManage.shareInstance.token) {
                        [PostManage.shareInstance logout:errorStr root:NO]; 
                    }
                    if (block) block(returnErrCode?@(errorCode):errorStr,NO);
                    return;
                }
            }else{
                errorStr = responseJSON[@"msg"] ;
                if ((!errorStr||!errorStr.length ) && ([responseJSON[@"data"] isKindOfClass:NSString.class] && [responseJSON[@"data"] length])) {
                    errorStr = responseJSON[@"data"];
                }
            }
        }else if ([responseJSON isKindOfClass:NSError.class]) {
            NSError *err = (NSError*)responseJSON;
            errorCode = err.code;
            errorStr = [responseJSON localizedDescription];
        }else{
            errorCode = response.statusCode;
            errorStr = self.errorInfo[@(response.statusCode)];
        }
    }else{
        errorCode = response.statusCode;
        errorStr = self.errorInfo[@(response.statusCode)];
    }
    if (showError) {
        if (!errorStr || ([errorStr isKindOfClass:NSString.class] && !errorStr.length)) errorStr = @"请求失败,请稍后再试";
        if (uploadFile) errorStr = @"上传失败,请稍后再试";
        if (showAuto) {
            PostAutoAlert(errorStr);
        }else{
            PostInfoView(errorStr,vc.view)
        }
    }
    
    if (block) block(returnErrCode?@(errorCode):errorStr,NO);
}

#pragma mark - responseJSON Error
-(void)handleResponse:(NSHTTPURLResponse*)response
       responseJSON:(id)responseJSON
      autoShowError:(NSArray*)infoArr
                 vc:(nullable UIViewController*)vc
              block:(nullable PostNetWorkBock)block{
    [self handleResponse:response responseJSON:responseJSON uploadFile:NO autoShowError:infoArr vc:vc block:block];
}

#pragma mark BaseURL
+ (NSString *)baseURLStr {
    return [self realURLWithKey:@"baseURL"];
}
+ (NSString *)imageURL{
    return [self realURLWithKey:@"imageURL"];
}
+ (NSString*)protocolURL{
     return [self realURLWithKey:@"protocolURL"];
}
+ (NSString *)realURLWithKey:(NSString *)key {
    NSString *environment = [self currentEnvironment]?:kCurrentEnvironment;
    NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"BSNetURL"ofType:@"plist"];
    NSDictionary*urlDic = [[[NSDictionary alloc] initWithContentsOfFile:plistPath] objectForKey:environment];
    return urlDic[key]?:@"";
}

+ (NSString *)currentEnvironment {
    return kCurrentEnvironment;
}
+ (void)changeEnvironmentTo:(NSString *)environment {
    if (!environment || environment.length <= 0) {
        environment = kCurrentEnvironment;
    }
    [BSNetAPIClient changeClient];
}

/// 生成32位UUID
- (NSString *)uuidString{
    CFUUIDRef uuid_ref = CFUUIDCreate(NULL);
    CFStringRef uuid_string_ref= CFUUIDCreateString(NULL, uuid_ref);
    NSString *uuid = [NSString stringWithString:(__bridge NSString *)uuid_string_ref];
    CFRelease(uuid_ref);
    CFRelease(uuid_string_ref);
    NSString *UUID = [[uuid lowercaseString] stringByReplacingOccurrencesOfString:@"-" withString:@""];
    return UUID;
}

- (NSDictionary *)errorInfo{
    if (!_errorInfo) {
        _errorInfo = @{
            @(400):@"Bad Request",
            @(401):@"Unauthorized",
            @(403):@"Forbidden",
            @(404):@"Not Found",
            @(405):@"Request Method Error",
            @(415):@"Unsupported Media Type",
            @(500):@"Internal Server Error",
            @(502):@"Bad Gateway",
            @(503):@"Service Unavailable",
        };
    }
    return _errorInfo;
}

@end
